package com.imooc.mall.service.impl;

import com.google.gson.Gson;
import com.imooc.mall.enums.ProductStatusEnum;
import com.imooc.mall.enums.ResponseEnum;
import com.imooc.mall.form.CartAddForm;
import com.imooc.mall.form.CartUpdateForm;
import com.imooc.mall.pojo.Cart;
import com.imooc.mall.service.CartService;
import com.imooc.mall.service.ProductService;
import com.imooc.mall.vo.CartProductVo;
import com.imooc.mall.vo.CartVo;
import com.imooc.mall.vo.ProductDetailVo;
import com.imooc.mall.vo.ResponseVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class CartServiceImpl implements CartService {

    private final static String CART_REDIS_KEY_TEMPLATE = "cart_%d";

    @Autowired
    private ProductService productService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private Gson gson = new Gson();

    /**
     * 自己写的版本
     * 写的不对，redis里面的数据只能用productId，其他数据从mysql里面查询新的。
     *
     */
//    @Override
//    public CartVo list(Integer uid) {
//        CartVo cartVo = new CartVo();
//        ArrayList<CartProductVo> cartProductVos = new ArrayList<>();
//        Boolean selectedAll = true;
//        BigDecimal cartTotalPrice = new BigDecimal(0);
//        int cartTotalQuantity = 0;
//
//        Set<Map.Entry<Object, Object>> entries = redisTemplate.opsForHash().entries(uid.toString()).entrySet();
//        for (Map.Entry<Object, Object> entry : entries) {
//            CartProductVo cartProductVo = gson.fromJson(entry.getValue().toString(), CartProductVo.class);
//            cartProductVos.add(cartProductVo);
//            if (!cartProductVo.getProductSelected()) {
//                selectedAll = false;
//            }
//            Integer singleQuantity = cartProductVo.getQuantity();
//            BigDecimal quantity = new BigDecimal(singleQuantity);
//            cartTotalPrice = cartTotalPrice.add(quantity.multiply(cartProductVo.getProductPrice()));
//            cartTotalQuantity += singleQuantity;
//        }
//
//        cartVo.setCartProductVoList(cartProductVos);
//        cartVo.setSelectedAll(selectedAll);
//        cartVo.setCartTotalPrice(cartTotalPrice);
//        cartVo.setCartTotalQuantity(cartTotalQuantity);
//        log.info("购物车的具体信息cartVo={}", gson.newBuilder().setPrettyPrinting().create().toJson(cartVo));
//        return cartVo;
//    }
    @Override
    public ResponseVo<CartVo> list(Integer uid) {
        CartVo cartVo = new CartVo();
        ArrayList<CartProductVo> cartProductVos = new ArrayList<>();
        Boolean selectedAll = true;
        BigDecimal cartTotalPrice = new BigDecimal(0);
        Integer cartTotalQuantity = 0;

        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);

        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();

        Map<String, String> entries = opsForHash.entries(redisKey);

        for (Map.Entry<String, String> entry : entries.entrySet()) {
            Integer productId = Integer.valueOf(entry.getKey());
            Cart cart = gson.fromJson(entry.getValue(), Cart.class);

            //TODO 需要优化，使用mysql里的in
            ResponseVo<ProductDetailVo> detail = productService.detail(productId);
            ProductDetailVo productDetailVo = detail.getData();
            if (productDetailVo != null) {
                CartProductVo cartProductVo = new CartProductVo(productId,
                        cart.getQuantity(),
                        productDetailVo.getName(),
                        productDetailVo.getSubtitle(),
                        productDetailVo.getMainImage(),
                        productDetailVo.getPrice(),
                        productDetailVo.getStatus(),
                        productDetailVo.getPrice().multiply(BigDecimal.valueOf(cart.getQuantity())),
                        productDetailVo.getStock(),
                        cart.getProductSelected());

                cartProductVos.add(cartProductVo);
                if (!cartProductVo.getProductSelected()) {
                    selectedAll = false;
                }

                if (cart.getProductSelected()) {
                    cartTotalPrice = cartTotalPrice.add(cartProductVo.getProductTotalPrice());
                }

                cartTotalQuantity += cart.getQuantity();
            }
        }

        cartVo.setCartProductVoList(cartProductVos);
        cartVo.setSelectedAll(selectedAll);
        cartVo.setCartTotalPrice(cartTotalPrice);
        cartVo.setCartTotalQuantity(cartTotalQuantity);
        log.info("购物车的具体信息cartVo={}", gson.newBuilder().setPrettyPrinting().create().toJson(cartVo));
        return ResponseVo.success(cartVo);
    }


    @Override
    public ResponseVo<CartVo> add(Integer uid, CartAddForm cartAddForm) {
        Integer quantity = 1;
        Integer productId = cartAddForm.getProductId();
        ResponseVo<ProductDetailVo> detail = productService.detail(productId);
        ProductDetailVo productDetailVo = detail.getData();
        //商品是否存在
        if (productDetailVo == null) {
            return ResponseVo.error(ResponseEnum.PRODUCT_NOT_EXIST);
        }

        //商品是否正常在售
        if (!productDetailVo.getStatus().equals(ProductStatusEnum.ON_SALE.getCode())) {
            return ResponseVo.error(ResponseEnum.PRODUCT_OFF_SALE_OR_DELETE);
        }

        //商品库存是否充足
        if (productDetailVo.getStock() <= 0) {
            return ResponseVo.error(ResponseEnum.PRODUCT_STOCK_ERROR);
        }

        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);

        String json1 = opsForHash.get(redisKey, productId.toString());
        Cart cart = null;
        if (StringUtils.isEmpty(json1)) {
            //没有该商品, 新增
            cart = new Cart(productId, quantity, cartAddForm.getSelected());
        } else {
            cart= gson.fromJson(json1, Cart.class);
            cart.setQuantity(cart.getQuantity() + quantity);
        }

        opsForHash.put(redisKey,
                String.valueOf(productId),
                gson.toJson(cart));

        return list(uid);
    }

    @Override
    public ResponseVo<CartVo> update(Integer uid, CartUpdateForm cartUpdateForm, Integer productId) {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);

        String json = opsForHash.get(redisKey, String.valueOf(productId));
        if (StringUtils.isEmpty(json)) {
            return ResponseVo.error(ResponseEnum.CART_PRODUCT_NOT_EXIST);
        }
        Cart cart = gson.fromJson(json, Cart.class);
        if (cartUpdateForm.getQuantity() != null
                && cartUpdateForm.getQuantity() >= 0) {
            cart.setQuantity(cartUpdateForm.getQuantity());
        }
        if (cartUpdateForm.getSelected() != null) {
            cart.setProductSelected(cartUpdateForm.getSelected());
        }

        opsForHash.put(redisKey, String.valueOf(productId), gson.toJson(cart));

        return list(uid);
    }

    @Override
    public ResponseVo<CartVo> delete(Integer uid, Integer productId) {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);

        String value = opsForHash.get(redisKey, String.valueOf(productId));
        if (StringUtils.isEmpty(value)) {
            //没有该商品, 报错
            return ResponseVo.error(ResponseEnum.CART_PRODUCT_NOT_EXIST);
        }

        opsForHash.delete(redisKey, String.valueOf(productId));
        return list(uid);
    }

    @Override
    public ResponseVo<CartVo> selectAll(Integer uid) {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);

        List<Cart> carts = listForCart(uid);
        for (Cart cart : carts) {
            cart.setProductSelected(true);
            opsForHash.put(redisKey, String.valueOf(cart.getProductId()), gson.toJson(cart));
        }

        return list(uid);
    }

    @Override
    public ResponseVo<CartVo> unSelectAll(Integer uid) {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);

        List<Cart> carts = listForCart(uid);
        for (Cart cart : carts) {
            cart.setProductSelected(false);
            opsForHash.put(redisKey, String.valueOf(cart.getProductId()), gson.toJson(cart));
        }

        return list(uid);
    }

    @Override
    public ResponseVo<Integer> quantitySum(Integer uid) {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, uid);

        Integer sum = listForCart(uid).stream()
                .map(Cart::getQuantity)
                .reduce(0, Integer::sum);

        return ResponseVo.success(sum);
    }

    @Override
    public List<Cart> listForCart(Integer uid) {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey  = String.format(CART_REDIS_KEY_TEMPLATE, uid);
        Map<String, String> entries = opsForHash.entries(redisKey);

        List<Cart> cartList = new ArrayList<>();
        for (Map.Entry<String, String> entry : entries.entrySet()) {
            cartList.add(gson.fromJson(entry.getValue(), Cart.class));
        }

        return cartList;
    }
}
